package operator

/**
  * 有理数类,能表示成分数的类
  * 1/2,2/3
  *
  */
class Rational(n: Int, d: Int) {
  // 构造体中非声明方法和变量的语句会包含到构造方法中
  // 判断参数是否为0
  require(d != 0)
  //  println("创建Rational类[" + zi + "/" + mu + "]")

  // 变量声明会被转换成类字段，且按从上到下初始化
  private val g = gcd(n, d)
  val zi = n / g
  val mu = d / g

  /**
    * 辅助构造函数，用于当分母为1的情况，只需要传入分子
    * 会调用主构造方法或其他辅助构造方法
    * @param n
    */
  def this(n: Int) = this(n, 1)

  /**
    * 定义与另个Rational类相加的方法,返回一个新的Rational对象
    *
    * @param rational
    * @return
    */
  def +(rational: Rational): Rational =
    new Rational(zi * rational.mu + rational.zi * mu, mu * rational.mu)


  /**
    * 重载+方法，传入整数
    *
    * @param i
    * @return
    */
  def +(i: Int): Rational =
    new Rational(zi + i * mu, mu)

  /**
    * 定义与另一个rational相乘的方法，
    * 因为该方法名是“*”开头的，所以计算优先级高于+，-
    *
    * @param rational
    * @return
    */
  def *(rational: Rational): Rational =
    new Rational(zi * rational.zi, mu * rational.mu)

  /**
    * 重载*方法 传入的是整数
    *
    * @param i
    * @return
    */
  def *(i: Int): Rational =
    new Rational(zi * i, mu)


  /**
    * 定义与另个Rational类相减的方法,返回一个新的Rational对象
    *
    * @param rational
    * @return
    */
  def -(rational: Rational): Rational =
    new Rational(zi * rational.mu - rational.zi * mu, mu * rational.mu)


  /**
    * 重载-方法，传入整数
    *
    * @param i
    * @return
    */
  def -(i: Int): Rational =
    new Rational(zi - i * mu, mu)

  /**
    * 定义与另一个rational相除的方法，
    * 因为该方法名是“/”开头的，所以计算优先级高于+，-
    *
    * @param rational
    * @return
    */
  def /(rational: Rational): Rational =
    new Rational(zi * rational.mu, mu * rational.zi)

  /**
    * 重载/方法 传入的是整数
    *
    * @param i
    * @return
    */
  def /(i: Int): Rational =
    new Rational(zi, mu * i)

  /**
    * 用辗转相除法求两个数最大公约数
    *
    * @param a
    * @param b
    * @return
    */
  private def gcd(a: Int, b: Int): Int =
    if (b == 0)
      a
    else
      gcd(b, a % b)


  // 重写toString方法
  override def toString: String = zi + "/" + mu
}
